﻿// See https://aka.ms/new-console-template for more information
using System.Runtime.Serialization.Formatters.Binary;

User obj1 = new User() { Id = 1, Name = "123" };
User obj2 = new User() { Id = 1, Name = "123" };
//Console.WriteLine(object.ReferenceEquals(obj1, obj2));
//User obj3 = new User();
//CopyValueObject(obj3, obj1);
//Console.WriteLine(obj3.Name);

User obj4 = new();
obj4.Id = 1;
obj4.Name = "123";
obj4.list = new List<int> { 1, 2, 3 };
obj4.test.TestName = "test";
var obj5 = (User)obj4.Clone();
Console.WriteLine(obj5.Id);
Console.WriteLine(obj5.Name);
Console.WriteLine(string.Join(null, obj5.list));
Console.WriteLine(obj5.test.TestName);
obj4.Id = 555;
obj4.Name = "898";
//obj4.list=new List<int> { 4,5,6 };这样写相当于重新赋值，内存地址都变更了
obj4.list.AddRange(new List<int> { 4, 5, 6 });
obj4.test.TestName = "abcabcabc";
Console.WriteLine(obj5.Id);
Console.WriteLine(obj5.Name);
Console.WriteLine(string.Join(null, obj5.list));
Console.WriteLine(obj5.test.TestName);

//浅拷贝是指创建一个新的对象，但是只复制了原对象的引用类型成员变量的值，而不复制引用类型成员变量本身。
//浅拷贝只复制对象本身和其值类型成员变量，而不复制引用类型成员变量。因此，如果原对象和复制对象共享同一个引用类型成员变量，那么对其中一个对象的修改会影响到另一个对象
//自己写的浅拷贝实现
void CopyValueObject<T>(T par1, T par2)
{
    //反射查询
    foreach (var item1 in par1.GetType().GetProperties())
    {
        foreach (var item2 in par2.GetType().GetProperties())
        {
            //如果是相同的属性
            if (item1.Name == item2.Name)
            {
                //反射赋值
                item1.SetValue(par1, item2.GetValue(par2));
            }
        }
    }
}

//深拷贝则会复制对象本身和其所有成员变量，包括引用类型成员变量。因此，复制对象和原对象是完全独立的，修改其中一个对象不会影响到另一个对象。
//深拷贝，序列化实现
T DeepClone<T>(T obj)
{
    using (MemoryStream stream = new MemoryStream())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, obj);
        stream.Seek(0, SeekOrigin.Begin);
        return (T)formatter.Deserialize(stream);
    }
}

//可以通过实现ICloneable接口来轻松实现浅拷贝
public class User : ICloneable
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<int> list { get; set; }

    public Test test { get; set; } = new();

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

public class Test
{
    public string TestName { get;set; }
}